В этом ноутбуке нам понадобятся библиотека NumPy
. Для удобства импортируем ее под более коротким именем:
In [1]:
import numpy as np
Самый простой способ создать вектор в NumPy
— задать его явно с помощью numpy.array(list, dtype=None, ...)
.
Параметр list
задает итерируемый объект, из которого можно создать вектор. Например, в качестве этого параметра можно задать список чисел. Параметр dtype
задает тип значений вектора, например, float
— для вещественных значений и int
— для целочисленных. Если этот параметр не задан, то тип данных будет определен из типа элементов первого аргумента.
In [2]:
a = np.array([1, 2, 3, 4])
print 'Вектор:\n', a
In [3]:
b = np.array([1, 2, 3, 4, 5], dtype=float)
print 'Вещественный вектор:\n', b
In [4]:
c = np.array([True, False, True], dtype=bool)
print 'Булевский вектор:\n', c
Тип значений вектора можно узнать с помощью numpy.ndarray.dtype
:
In [5]:
print 'Тип булевского вектора:\n', c.dtype
Другим способом задания вектора является функция numpy.arange(([start, ]stop, [step, ]...)
, которая задает последовательность чисел заданного типа из промежутка [start
, stop
) через шаг step
:
In [6]:
d = np.arange(start=10, stop=20, step=2) # последнее значение не включается!
print 'Вектор чисел от 10 до 20 с шагом 2:\n', d
In [7]:
f = np.arange(start=0, stop=1, step=0.3, dtype=float)
print 'Вещественный вектор чисел от 0 до 1 с шагом 0.3:\n', f
По сути вектор в NumPy
является одномерным массивом, что соответствует интуитивному определению вектора:
In [8]:
print c.ndim # количество размерностей
In [9]:
print c.shape # shape фактически задает длину вектора
Обратите внимание: _вектор _и одномерный массив тождественные понятия в NumPy
. Помимо этого, также существуют понятия вектор-столбец и вектор-строка, которые, несмотря на то что математически задают один и тот же объект, являются двумерными массивами и имеют другое значение поля shape
(в этом случае поле состоит из двух чисел, одно из которых равно единице). Эти тонкости будут рассмотрены в следующем уроке.
Более подробно о том, как создавать векторы в NumPy
,
см. документацию.
Векторы в NumPy
можно складывать, вычитать, умножать на число и умножать на другой вектор (покоординатно):
In [10]:
a = np.array([1, 2, 3])
b = np.array([6, 5, 4])
k = 2
print 'Вектор a:', a
print 'Вектор b:', b
print 'Число k:', k
In [11]:
print 'Сумма a и b:\n', a + b
In [12]:
print 'Разность a и b:\n', a - b
In [13]:
print 'Покоординатное умножение a и b:\n', a * b
In [14]:
print 'Умножение вектора на число (осуществляется покоординатно):\n', k * a
Вспомним некоторые нормы, которые можно ввести в пространстве $\mathbb{R}^{n}$, и рассмотрим, с помощью каких библиотек и функций их можно вычислять в NumPy
.
p-норма (норма Гёльдера) для вектора $x = (x_{1}, \dots, x_{n}) \in \mathbb{R}^{n}$ вычисляется по формуле:
$$ \left\Vert x \right\Vert_{p} = \left( \sum_{i=1}^n \left| x_{i} \right|^{p} \right)^{1 / p},~p \geq 1. $$В частных случаях при:
Далее нам понабится модуль numpy.linalg
, реализующий некоторые приложения линейной алгебры. Для вычисления различных норм мы используем функцию numpy.linalg.norm(x, ord=None, ...)
, где x
— исходный вектор, ord
— параметр, определяющий норму (мы рассмотрим два варианта его значений — 1 и 2). Импортируем эту функцию:
In [15]:
from numpy.linalg import norm
$\ell_{1}$ норма (также известная как манхэттенское расстояние) для вектора $x = (x_{1}, \dots, x_{n}) \in \mathbb{R}^{n}$ вычисляется по формуле:
$$ \left\Vert x \right\Vert_{1} = \sum_{i=1}^n \left| x_{i} \right|. $$Ей в функции numpy.linalg.norm(x, ord=None, ...)
соответствует параметр ord=1
.
In [16]:
a = np.array([1, 2, -3])
print 'Вектор a:', a
In [17]:
print 'L1 норма вектора a:\n', norm(a, ord=1)
$\ell_{2}$ норма (также известная как евклидова норма) для вектора $x = (x_{1}, \dots, x_{n}) \in \mathbb{R}^{n}$ вычисляется по формуле:
$$ \left\Vert x \right\Vert_{2} = \sqrt{\sum_{i=1}^n \left( x_{i} \right)^2}. $$Ей в функции numpy.linalg.norm(x, ord=None, ...)
соответствует параметр ord=2
.
In [18]:
a = np.array([1, 2, -3])
print 'Вектор a:', a
In [19]:
print 'L2 норма вектора a:\n', norm(a, ord=2)
Более подробно о том, какие еще нормы (в том числе матричные) можно вычислить, см. документацию.
Для двух векторов $x = (x_{1}, \dots, x_{n}) \in \mathbb{R}^{n}$ и $y = (y_{1}, \dots, y_{n}) \in \mathbb{R}^{n}$ $\ell_{1}$ и $\ell_{2}$ раccтояния вычисляются по следующим формулам соответственно:
$$ \rho_{1}\left( x, y \right) = \left\Vert x - y \right\Vert_{1} = \sum_{i=1}^n \left| x_{i} - y_{i} \right| $$$$ \rho_{2}\left( x, y \right) = \left\Vert x - y \right\Vert_{2} = \sqrt{\sum_{i=1}^n \left( x_{i} - y_{i} \right)^2}. $$
In [20]:
a = np.array([1, 2, -3])
b = np.array([-4, 3, 8])
print 'Вектор a:', a
print 'Вектор b:', b
In [21]:
print 'L1 расстояние между векторами a и b:\n', norm(a - b, ord=1)
In [22]:
print 'L2 расстояние между векторами a и b:\n', norm(a - b, ord=2)
Также расстояние между векторами можно посчитать с помощью функции scipy.spatial.distance.cdist(XA, XB, metric='euclidean', p=2, ...)
из модуля SciPy
, предназначенного для выполнения научных и инженерных расчётов.
In [23]:
from scipy.spatial.distance import cdist
scipy.spatial.distance.cdist(...)
требует, чтобы размерность XA
и XB
была как минимум двумерная. По этой причине для использования этой функции необходимо преобразовать векторы, которые мы рассматриваем в этом ноутбуке, к вектор-строкам с помощью способов, которые мы рассмотрим ниже.
Параметры XA, XB
— исходные вектор-строки, а metric
и p
задают метрику расстояния
(более подробно о том, какие метрики можно использовать, см. документацию).
Первый способ из вектора сделать вектор-строку (вектор-столбец) — это использовать метод array.reshape(shape)
, где параметр shape
задает размерность вектора (кортеж чисел).
In [24]:
a = np.array([6, 3, -5])
b = np.array([-1, 0, 7])
print 'Вектор a:', a
print 'Его размерность:', a.shape
print 'Вектор b:', b
print 'Его размерность:', b.shape
In [25]:
a = a.reshape((1, 3))
b = b.reshape((1, 3))
print 'После применения метода reshape:\n'
print 'Вектор-строка a:', a
print 'Его размерность:', a.shape
print 'Вектор-строка b:', b
print 'Его размерность:', b.shape
In [26]:
print 'Манхэттенское расстояние между a и b (через cdist):', cdist(a, b, metric='cityblock')
Заметим, что после применения этого метода размерность полученных вектор-строк будет равна shape
. Следующий метод позволяет сделать такое же преобразование, но не изменяет размерность исходного вектора.
В NumPy
к размерностям объектов можно добавлять фиктивные оси с помощью np.newaxis
. Для того, чтобы понять, как это сделать, рассмотрим пример:
In [27]:
d = np.array([3, 0, 8, 9, -10])
print 'Вектор d:', d
print 'Его размерность:', d.shape
In [28]:
print 'Вектор d с newaxis --> вектор-строка:\n', d[np.newaxis, :]
print 'Полученная размерность:', d[np.newaxis, :].shape
print 'Вектор d с newaxis --> вектор-столбец:\n', d[:, np.newaxis]
print 'Полученная размерность:', d[:, np.newaxis].shape
Важно, что np.newaxis
добавляет к размерности ось, длина которой равна 1 (это и логично, так как количество элементов должно сохраняться). Таким образом, надо вставлять новую ось там, где нужна единица в размерности.
Теперь посчитаем расстояния с помощью scipy.spatial.distance.cdist(...)
, используя np.newaxis
для преобразования векторов:
In [29]:
a = np.array([6, 3, -5])
b = np.array([-1, 0, 7])
print 'Евклидово расстояние между a и b (через cdist):', cdist(a[np.newaxis, :],
b[np.newaxis, :],
metric='euclidean')
Эта функция также позволяет вычислять попарные расстояния между множествами векторов. Например, пусть у нас имеется матрица размера $m_{A} \times n$. Мы можем рассматривать ее как описание некоторых $m_{A}$ наблюдений в $n$-мерном пространстве. Пусть также имеется еще одна аналогичная матрица размера $m_{B} \times n$, где $m_{B}$ векторов в том же $n$-мерном пространстве. Часто необходимо посчитать попарные расстояния между векторами первого и второго множеств. В этом случае можно пользоваться функцией scipy.spatial.distance.cdist(XA, XB, metric='euclidean', p=2, ...)
, где в качестве XA, XB
необходимо передать две описанные матрицы. Функция возвращает матрицу попарных расстояний размера $m_{A} \times m_{B}$, где элемент матрицы на $[i, j]$-ой позиции равен расстоянию между $i$-тым вектором первого множества и $j$-ым вектором второго множества.
В данном случае эта функция предподчительнее numpy.linalg.norm(...)
, так как она вычисляет попарные расстояния быстрее и эффективнее.
In [30]:
a = np.array([0, 5, -1])
b = np.array([-4, 9, 3])
print 'Вектор a:', a
print 'Вектор b:', b
Скалярное произведение в пространстве $\mathbb{R}^{n}$ для двух векторов $x = (x_{1}, \dots, x_{n})$ и $y = (y_{1}, \dots, y_{n})$ определяется как:
$$ \langle x, y \rangle = \sum_{i=1}^n x_{i} y_{i}. $$Скалярное произведение двух векторов можно вычислять с помощью функции numpy.dot(a, b, ...)
или метода vec1.dot(vec2)
, где vec1
и vec2
— исходные векторы. Также эти функции подходят для матричного умножения, о котором речь пойдет в следующем уроке.
In [31]:
print 'Скалярное произведение a и b (через функцию):', np.dot(a, b)
In [32]:
print 'Скалярное произведение a и b (через метод):', a.dot(b)
Длиной вектора $x = (x_{1}, \dots, x_{n}) \in \mathbb{R}^{n}$ называется квадратный корень из скалярного произведения, то есть длина равна евклидовой норме вектора:
$$ \left| x \right| = \sqrt{\langle x, x \rangle} = \sqrt{\sum_{i=1}^n x_{i}^2} = \left\Vert x \right\Vert_{2}. $$Теперь, когда мы знаем расстояние между двумя ненулевыми векторами и их длины, мы можем вычислить угол между ними через скалярное произведение:
$$ \langle x, y \rangle = \left| x \right| | y | \cos(\alpha) \implies \cos(\alpha) = \frac{\langle x, y \rangle}{\left| x \right| | y |}, $$где $\alpha \in [0, \pi]$ — угол между векторами $x$ и $y$.
In [33]:
cos_angle = np.dot(a, b) / norm(a) / norm(b)
print 'Косинус угла между a и b:', cos_angle
print 'Сам угол:', np.arccos(cos_angle)
Более подробно о том, как вычислять скалярное произведение в NumPy
,
см. документацию.